package joc.internal.transformer;

import java.lang.annotation.Annotation;

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;
import joc.contract.Getter;
import joc.internal.EvaluationResult;
import joc.internal.Evaluator;
import joc.internal.compiler.CompareExp;
import joc.internal.compiler.ConstructorExp;
import joc.internal.compiler.NestedExp;
import joc.internal.compiler.StandaloneExp;
import joc.internal.compiler.StaticCallExp;
import joc.internal.compiler.ValueExp;
import joc.internal.transformer.helper.GetterExpressionEditor;

public class GetterTransformer extends GetterSetterTransformer {

	public GetterTransformer(Transformer transformer) {
		super(transformer);
	}

	@Override
	public Class<? extends Annotation> getAnnotationClass() {
		return Getter.class;
	}

	@Override
	protected String getMethodPrefix(CtMethod method) throws Exception {
		if (method.getReturnType().equals(CtClass.booleanType)) {
			return "is";
		}
		return "get";
	}

	@Override
	public int getExpectedNumberOfMethodArguments() {
		return 0;
	}

	@Override
	protected void individualCheck(CtMethod method, CtField field) throws NotFoundException, CannotCompileException {
		if (!field.getType().equals(method.getReturnType())) {
			insertError("Getter return-value has different type than the corresponding field.", method, true);
			return;
		}
		GetterExpressionEditor expressionEditor = new GetterExpressionEditor(this, field);
		method.instrument(expressionEditor);
		if (!expressionEditor.isReadField()) {
			insertError("Getter did not read field " + field.getName() + ".", method,
					!expressionEditor.isErrorOccurred());
			return;
		}
		NestedExp evaluationResult = new ConstructorExp(EvaluationResult.class,
				new ValueExp(getRecipientString(method)), new ValueExp(Getter.class), new CompareExp(
						NestedExp.field(field.getName())).eq(NestedExp.RETURN_VALUE), new ValueExp(
						"Getter did not return the corresponding field."));
		StandaloneExp exp = new StaticCallExp(Evaluator.evaluateContract, evaluationResult).toStandalone();
		getLogger().info("inserted after: " + exp.getCode());
		exp.insertAfter(method);
	}

}
